package ro.myApp.commons.basic;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;

import org.hibernate.validator.NotEmpty;

/**
 * @author anamaria
 * @version 1.0
 * @created 20-feb.-2010 01:12:14
 */
@MappedSuperclass
public abstract class PersistentEntity implements Deletable, Identifiable,
		Comparable<PersistentEntity>, Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2677351585974130138L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	@Version
	private Integer version;

	private boolean deleted;

	private String code;

	private String label = "";

	@Column(length = 4000)
	private String description = "";

	@NotEmpty
	@Column(nullable = false)
	private String createdByUsername;

	@Column(nullable = true)
	private String updatedByUsername;

	@Temporal(value = TemporalType.TIMESTAMP)
	@Column(nullable = false)
	private Date dateCreated;

	@Temporal(value = TemporalType.TIMESTAMP)
	@Column(nullable = true)
	private Date dateUpdated;

	@Column(name = "entity_type")
	private String type = this.getClass().getSimpleName();

	public PersistentEntity() {
		// do nothing
	}

	public PersistentEntity(Long id, String label) {
		super();
		this.id = id;
		this.label = label;
	}

	public PersistentEntity(Long id, Integer version, boolean deleted,
			String code, String label, String description,
			String createdByUsername, String updatedByUsername,
			Date dateCreated, Date dateUpdated, String type) {
		super();
		this.id = id;
		this.version = version;
		this.deleted = deleted;
		this.code = code;
		this.label = label;
		this.description = description;
		this.createdByUsername = createdByUsername;
		this.updatedByUsername = updatedByUsername;
		this.dateCreated = dateCreated;
		this.dateUpdated = dateUpdated;
		this.type = type;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public boolean isDeleted() {
		return deleted;
	}

	public void setDeleted(boolean deleted) {
		this.deleted = deleted;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	public String getCreatedByUsername() {
		return createdByUsername;
	}

	public void setCreatedByUsername(String createdByUsername) {
		this.createdByUsername = createdByUsername;
	}

	public String getUpdatedByUsername() {
		return updatedByUsername;
	}

	public void setUpdatedByUsername(String updatedByUsername) {
		this.updatedByUsername = updatedByUsername;
	}

	public Date getDateCreated() {
		return dateCreated;
	}

	public void setDateCreated(Date dateCreated) {
		this.dateCreated = dateCreated;
	}

	public Date getDateUpdated() {
		return dateUpdated;
	}

	public void setDateUpdated(Date dateUpdated) {
		this.dateUpdated = dateUpdated;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getType() {
		return type;
	}

	public Integer getVersion() {
		return version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	@Override
	public int hashCode() {
		if (this.id == null)
			return super.hashCode();
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final PersistentEntity other = (PersistentEntity) obj;
		if (id == null) {
			if (other.id != null)
				return false;
			return super.equals(obj);
		} else if (!id.equals(other.id))
			return false;
		return true;
	}

	@Override
	public int compareTo(PersistentEntity o) {
		if (this.dateCreated == null)
			return -1;
		return this.dateCreated.compareTo(o.dateCreated);
	}

	@Override
	public Object clone() {
		ObjectOutputStream oos = null;
		ObjectInputStream ois = null;
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(bos);
			oos.writeObject(this);
			oos.flush();
			oos.close();
			ByteArrayInputStream bin = new ByteArrayInputStream(
					bos.toByteArray());
			ois = new ObjectInputStream(bin);
			Object clone = ois.readObject();
			ois.close();
			return clone;
		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public String toString() {
		return String.format("PersistentEntity [id = %s, code = %s, type = %s]", id, code, type);
	}

	@PrePersist
	public void onInsert() {
		this.dateCreated = new Date();
	}

	@PreUpdate
	public void onUpdate() {
		this.dateUpdated = new Date();
	}
}